#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;
class Edge
{
    public:
    int to;
    Edge *next;
};

class Graph
{
    static const int MVN=1000100,MARCN=MVN*2;
    public:
    int vn,arcn;
    Edge *edge,*head[MVN];
    Graph(int n=0)
    {
        init(n);
        edge=new Edge[MARCN];
    };
    void init(int n)
    {
        vn=n;
        arcn=0;
        fill(head,head+MVN,(Edge*)NULL);
    }
    void add(int vs,int vt)
    {
        edge[arcn].to=vt;
        edge[arcn].next=head[vs];
        head[vs]=&edge[arcn++];
    }
};
int n,m,k;
bool done[1000100];
Graph g;
int cnt;
void dfs(int vs)
{
	cnt++;
	done[vs]=true;
	for(Edge *ep=g.head[vs];ep;ep=ep->next) if(!done[ep->to])
	{
		dfs(ep->to);
	}
}
int getAns()
{
	int dv=0;
	priority_queue<int,vector<int>,greater<int> > q;
	for(int i=1;i<=n;i++) if(!done[i])
	{
		cnt=0;
		dfs(i);
		int t=min(cnt,k);
		dv+=t;
		q.push(t);
	}
	int ans=0;
	while(dv<(q.size()-1)*2)
	{
		//printf("dv:%d %d\n",dv,(q.size()-1)*2);
		ans++;
		int t1=q.top();q.pop();
		int t2=q.top();q.pop();
		//cout<<t1<<" "<<t2<<endl;
		if(t1+t2>k) dv-=(t1+t2-k);
		q.push(min(t1+t2,k));
	}
	return ans;
}
int main()
{
	cin>>n>>m>>k;
	g.init(n+1);
	for(int i=0;i<m;i++)
	{
		int v1,v2;
		scanf("%d%d",&v1,&v2);
		g.add(v1,v2);
		g.add(v2,v1);
	}
	cout<<getAns()<<endl;
	return 0;
}
